import random
import time
import os

from yysautomatic.setting import locate_cache_time
from yysautomatic.log import get_logger
from .event import EventType
from .gui import gui

logger = get_logger(__name__)


class Component(object):

    def __init__(self, parent=None):
        self.__parent = None
        self.__x = -1
        self.__y = -1
        self.__w = 0
        self.__h = 0
        self.__last_locate_result = (-1, False)
        self.__parent = parent

    @property
    def children(self):
        children = []
        exclude_attr = ['children', 'parent']
        for x in self.__dir__():
            if not x.startswith('_') and x not in exclude_attr and hasattr(self, x):
                attr = getattr(self, x)
                if isinstance(attr, Component):
                    children.append(attr)
        return children

    @property
    def parent(self):
        return self.__parent

    @property
    def rect(self):
        return self.__x, self.__y, self.__w, self.__h

    @property
    def client_rect(self):
        """
        :return: 组件位置(left, top ,width, height)
        """
        x = self.__x
        y = self.__y
        parent = self.__parent
        while parent is not None:
            px, py, pw, ph = parent.rect
            x += px
            y += py
            parent = parent.parent
        return x, y, self.__w, self.__h

    def set_location_rect(self, location_rect):
        """
        设置组件位置
        :param location_rect:
        """
        if len(location_rect) == 2:
            x, y = location_rect
            self.__x = x
            self.__y = y
        else:
            x, y, w, h = location_rect
            self.__x = x
            self.__y = y
            self.__w = w
            self.__h = h

    def reset(self):
        """
        重置组件状态
        """
        self.set_location_rect((-1, -1))
        self.__last_locate_result = (-1, False)
        for child in self.children:
            child.reset()

    def on_show(self, listener):
        """
        组件显示事件
        :param listener: 事件回调
        :return: 事件ID
        """
        return self.add_listener(EventType.SHOW, self, listener)

    def add_listener(self, event_type, source, listener):
        """
        添加组件事件
        :param source: 组件
        :param event_type: 事件类型，见event.EventType
        :param listener: 事件回调
        :return: 事件ID
        """
        if self.__parent is not None:
            return self.__parent.add_listener(event_type, source, listener)
        else:
            raise NotImplementedError

    def remove_listener(self, listener_id):
        """
        移除事件
        :param listener_id: 事件ID
        :return:
        """
        if self.__parent is not None:
            self.__parent.remove_listener(listener_id)

    def locate(self):
        last_timestamp, last_is_show = self.__last_locate_result
        if last_timestamp < 0 or int(time.time() * 1000) - last_timestamp > locate_cache_time:
            is_show = self._locate()
            self.__last_locate_result = (int(time.time() * 1000), is_show)
            return is_show
        else:
            return last_is_show

    def _locate(self):
        """
        定位组件在窗口中的位置
        :return:
        """
        raise NotImplementedError


class Panel(Component):

    def __init__(self, parent=None):
        super().__init__()
        if parent is not None:
            (px, py, pw, ph) = parent.rect
            self.set_location_rect((0, 0, pw, ph))

    def reset(self):
        super().reset()
        self.set_location_rect((0, 0))

    def _locate(self):
        if hasattr(self, 'keys'):
            for x in getattr(self, 'keys'):
                if not x.locate():
                    return False
            return True
        else:
            raise 'Not keys for Panel locate'


class Label(Component):

    def __init__(self, parent, image):
        super().__init__(parent)
        self.__image = image
        self.__name = os.path.splitext(os.path.basename(image))[0]

    def _locate(self):
        logger.debug('检测组件%s位置开始...%s', self.__name, self.parent.win_id)
        x, y, w, h = self.rect
        region = self.client_rect if x >= 0 and y >= 0 else self.parent.client_rect
        logger.debug('检测组件%s范围: %s, %s', self.__name, region, self.parent.win_id)
        result = gui.locate(self.__image, region=region)
        if result is None:
            logger.debug('未检测到组件%s', self.__name)
            return False
        logger.debug('检测到组件%s位置: %s', self.__name, result)
        nx, ny, nw, nh = result
        px, py, pw, ph = self.parent.client_rect
        self.set_location_rect((nx - px, ny - py, nw, nh))
        logger.debug('更新组件%s位置: %s', self.__name, self.rect)
        return True


class Button(Label):

    def click(self, *args, **kwargs):
        client_x, client_y, w, h = self.client_rect
        x = client_x + random.randint(0, w)
        y = client_y + random.randint(0, h)
        logger.debug('点击位置: %s, %s', x, y)
        gui.click(x, y, *args, **kwargs)
